<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BUIAjaxObj
 *
 * @author Wang Jian Feng
 */
class BUIControl extends BUIBase {

    protected $ajaxContainerId = null;
    protected $layoutView = null;
    protected $name = null;
    protected $views = array();
    protected $containerView = null;
    protected $controls = array();
    protected $node = null;
    protected $id = null;
    protected $viewPath = null;
    protected $viewTemplate = null;
    protected $parentControl = null;
    protected $sender = null;
    private static $uCount = 0;
    protected $isRendered = false;
    protected $isPrepared = false;
    protected $linkIndex = array();
    protected $ajaxLinkIndex = array();

    public function __construct($name = NULL) {
        if ($name != NULL)
            $this->name = $name;
    }

    public static function getUniqueId() {
        static $count = 0;
        $count++;
        return $count;
    }

    /**
     * each control should have unique name according to node
     * @param type $data
     * @return type
     */
    public function getId($data = NULL) {
        if ($this->id == NULL) {
            if ($this instanceof BUINode) {
                if ($this->getNode() instanceof BNode) {
                    $this->id = strtolower(get_class($this->getNode())) . '_' . $this->getNode()->getId();
                    $this->id .= '_' . strtolower($this->getName());
                }
            } else {
                /*
                  if ($this->parentControl instanceof BUIControl) {
                  $parentId = $this->parentControl->getId();
                  $this->id .= $parentId . '_' . strtolower($this->getName());
                  }
                 * 
                 */
                $node = Blyn::app()->getCurrentNode();
                $this->id = strtolower(get_class($node)) . '_' . $node->getId();
                $this->id .= '_' . strtolower($this->getName());
            }
        }
        return $this->id;
    }

    public function setId($id, $data = NULL) {
        if ($id != NULL)
            $this->id = $id;
    }

    /**
     * 
     * @param type $name
     * @param array $data
     * @param type $sender, which control trigger the ajax request
     * @param type $updateControl, map to control that content will refresh by ajax request
     * @return type
     */
    public function getAjaxLink($name, $data = array(), $sender = NULL, $route = 'site/index', $updateControl = NULL) {
        //support update view with containerId
        if (is_array($updateControl)) {
            $containerId = isset($updateControl['ajaxContainerId']) ? $updateControl['ajaxContainerId'] : NULL;
            $updateView = isset($updateControl['updateView']) ? $updateControl['updateView'] : (isset($updateControl['view']) ? $updateControl['view'] : NULL);
            if (is_string($containerId) && $containerId != NULL) {
                $updateControl = new BUIControl('no-name');
                $updateControl->setAjaxContainerId($containerId);
            } else {
                $updateControl = $this;
            }
            if ($updateView == NULL)
                $updateControl->setLayoutView($this->getLayoutView());
            else {
                if (is_string($updateView))
                    $updateControl->addRenderView($updateView, $updateView);
                if (is_array($updateView)) {
                    $updateControl->addRenderView($updateView['view'], $updateView['view'], $updateView['data']);
                }
            }
        }

        if (!$updateControl instanceof BUIControl)
            $updateControl = $this;

        if (!$sender instanceof BUIControl)
            $sender = $this;

        if (isset($data['ajaxContainerId']) && $data['ajaxContainerId'] != NULL) {
            $ajaxContainerId = $data['ajaxContainerId'];
            unset($data['ajaxContainerId']);
        } else {
            $ajaxContainerId = $updateControl->getAjaxContainerId();
        }

        $layoutView = $updateControl->getLayoutView();

        //by default, set start point is screen
        if ($ajaxContainerId == NULL || $layoutView == NULL) {
            $ajaxContainerId = BUIBase::ajaxContainter_screen;
            $layoutView = Blyn::app()->getUIManager()->getCurrentScreen()->getLayoutView();
        }

        $viewData = array();
        if (isset($data['ajaxView']) && $data['ajaxView'] != NULL) {
            $ajaxView = $data['ajaxView'];
            unset($data['ajaxView']);
            if (is_string($ajaxView))
                $layoutView = $ajaxView;
            if (is_array($ajaxView)) {
                if (isset($ajaxView[0]))
                    $layoutView = $ajaxView[0];
                if (isset($ajaxView['view']))
                    $layoutView = $ajaxView['view'];
                if (isset($ajaxView['data']))
                    $viewData = $ajaxView['data'];
            }
        }

        if ($route == NULL) {
            $route = 'site/index';
        }
        $url = $updateControl->getUrl(NULL, $route);

        if ($url == NULL)
            $url = Blyn::app()->getUIManager()->getCurrentScreen()->getUrl(NULL, $route);

        //set ajaxLinkId
        $linkId = NULL;
        if (is_string($name)) {
            $linkId = $name;
        }
        if (is_array($name) && isset($name['name']) && $name['name'] !== NULL) {
            if (isset($name['ajaxLinkId']))
                $linkId = $name['ajaxLinkId'];
            if (isset($name['linkId']))
                $linkId = $name['linkId'];
            if (isset($name['id']))
                $linkId = $name['id'];
            //$name = $linkId;
            if (isset($name['name']))
                $name = $name['name'];
        }

        if (isset($data['ajaxLinkId']))
            $linkId = $data['ajaxLinkId'];

        $data['theLinkId'] = $linkId;

        if (!isset($this->linkIndex[$linkId])) {
            $this->linkIndex[$linkId] = 1;
        } else {
            $this->linkIndex[$linkId] ++;
        }
        $data['theLinkIndex'] = $this->linkIndex[$linkId];

        $data['ajaxLinkId'] = $linkId == NULL ? $sender->getName() . "_" . str_replace(" ", "_", $name) : $sender->getName() . "_" . str_replace(" ", "_", $linkId);

        if (isset($data['controlData'])) {
            $controlData = $data['controlData'];
            unset($data['controlData']);
        } else
            $controlData = $updateControl->parseIntoArray();

        if (isset($data['senderData'])) {
            $senderData = $data['senderData'];
            unset($data['senderData']);
        } else
            $senderData = $sender->parseIntoArray();

        $viewData['control'] = $controlData;
        $viewData['sender'] = $senderData;
        $viewData['updateControl'] = $controlData;

        return $this->createAjaxLink($name, $url, $ajaxContainerId, array('view' => $layoutView,
                    'data' => $viewData), $data);
    }

    /**
     * this function use to generate url for ajax request, if want use own ajax script, use this function to
     * generate url, it will also generate senderControl and updateControl
     * @param type $linkId
     * @param mix $updateControl, can be BUIControl, array or string
     * if array, usually should be like format: array('ajaxContainerId'=>'containerId','view'=>'view for render')
     * if string, will use to find view, and then use sender container id for update
     * @param type $route
     * @param type $sender
     */
    public function getAjaxLinkUrl($linkId, $updateControl = NULL, $data = array(), $route = 'site/index', $sender = null) {
        if (!$sender instanceof BUIControl)
            $sender = $this;
        if ($updateControl == NULL)
            $updateControl = $sender;

        if (!$updateControl instanceof BUIControl) {
            $containerId = $sender->getAjaxContainerId();
            $updateView = NULL;
            if (is_array($updateControl)) {
                if (isset($updateControl['ajaxContainerId']) && $updateControl['ajaxContainerId'] != NULL)
                    $containerId = $updateControl['ajaxContainerId'];
                if (isset($updateControl['view']) && $updateControl['view'] != NULL)
                    $updateView = $updateControl['view'];
            }
            if (is_string($updateControl))
                $containerId = $updateControl;
            if ($containerId != NULL) {
                $updateControl = new BUIControl();
                $updateControl->setAjaxContainerId($containerId);
                if ($updateView != NULL)
                    $updateControl->setLayoutView($updateView);
            }
        }

        if ($updateControl instanceof BUIControl && $sender instanceof BUIControl) {
            $url = $updateControl->getUrl(NULL, $route);

            if ($url == NULL)
                $url = Blyn::app()->getUIManager()->getCurrentScreen()->getUrl(NULL, $route);

            $data['theLinkId'] = $linkId;

            $linkId = $sender->getName() . "_" . str_replace(" ", "_", $linkId);
            $linkId = md5($linkId);

            $updateControlData = $updateControl->parseIntoArray();
            $senderData = $sender->parseIntoArray();

            if (is_array($data)) {
                if (isset($data['htmlOptions']))
                    unset($data['htmlOptions']);
                foreach ($data as $key => $value) {
                    if (is_string($value) || $value == NULL)
                        $url[$key] = $value; //add data into get 
                    else {//add data as session variable
                        $linkObj = new BUILink($linkId);
                        $linkObj->addLinkVariable($key, $value);
                    }
                }
            }

            if (is_array($url)) {
                $url['b_ajaxLinkId'] = $linkId;
                $route = $url[0];
                unset($url[0]);
                $params = $url;
                $url = yii::app()->getController()->createUrl($route, $params);
            } else if (is_string($url)) {
                $route = $url;
                $url = yii::app()->getController()->createUrl($route, array('b_ajaxLinkId' => $linkId));
            }

            $currentAjaxViews = Blyn::app()->getCurrentUser()->getContextVariable('currentAjaxViews');
            if ($currentAjaxViews == NULL)
                $currentAjaxViews = array();

            $updateView = $updateControl->getLayoutView();
            $updateViewData = array('senderControl' => $senderData, 'updateControl' => $updateControlData, 'control' => $updateControlData);

            $currentAjaxViews[$linkId] = array('view' => $updateView, 'data' => $updateViewData);

            Blyn::app()->getCurrentUser()->addContextVariable('currentAjaxViews', $currentAjaxViews);

            if ($url != NULL)
                return $url;
        }
    }

    public function getAjaxScript($name, $data = array(), $sender = NULL, $route = 'site/index', $updateControl = NULL) {
        //support update view with containerId
        if (is_array($updateControl)) {
            $containerId = isset($updateControl['ajaxContainerId']) ? $updateControl['ajaxContainerId'] : NULL;
            $updateView = isset($updateControl['updateView']) ? $updateControl['updateView'] : (isset($updateControl['view']) ? $updateControl['view'] : NULL);
            if (is_string($containerId) && $containerId != NULL) {
                $updateControl = new BUIControl('no-name');
                $updateControl->setAjaxContainerId($containerId);
            } else {
                $updateControl = $this;
            }
            if ($updateView == NULL)
                $updateControl->setLayoutView($this->getLayoutView());
            else {
                if (is_string($updateView))
                    $updateControl->addRenderView($updateView, $updateView);
                if (is_array($updateView)) {
                    $updateControl->addRenderView($updateView['view'], $updateView['view'], $updateView['data']);
                }
            }
        }

        if (!$updateControl instanceof BUIControl)
            $updateControl = $this;

        if (!$sender instanceof BUIControl)
            $sender = $this;

        if (isset($data['ajaxContainerId']) && $data['ajaxContainerId'] != NULL) {
            $ajaxContainerId = $data['ajaxContainerId'];
            unset($data['ajaxContainerId']);
        } else {
            $ajaxContainerId = $updateControl->getAjaxContainerId();
        }

        $layoutView = $updateControl->getLayoutView();

        //by default, set start point is screen
        if ($ajaxContainerId == NULL || $layoutView == NULL) {
            $ajaxContainerId = BUIBase::ajaxContainter_screen;
            $layoutView = Blyn::app()->getUIManager()->getCurrentScreen()->getLayoutView();
        }

        $viewData = array();
        if (isset($data['ajaxView']) && $data['ajaxView'] != NULL) {
            $ajaxView = $data['ajaxView'];
            unset($data['ajaxView']);
            if (is_string($ajaxView))
                $layoutView = $ajaxView;
            if (is_array($ajaxView)) {
                if (isset($ajaxView[0]))
                    $layoutView = $ajaxView[0];
                if (isset($ajaxView['view']))
                    $layoutView = $ajaxView['view'];
                if (isset($ajaxView['data']))
                    $viewData = $ajaxView['data'];
            }
        }

        $url = $updateControl->getUrl(NULL, $route);

        if ($url == NULL)
            $url = Blyn::app()->getUIManager()->getCurrentScreen()->getUrl(NULL, $route);

        //set ajaxLinkId
        $linkId = NULL;
        if (is_string($name)) {
            $linkId = $name;
        }
        if (is_array($name) && isset($name['name']) && $name['name'] != NULL) {
            if (isset($name['ajaxLinkId']))
                $linkId = $name['ajaxLinkId'];
            if (isset($name['linkId']))
                $linkId = $name['linkId'];
            if (isset($name['id']))
                $linkId = $name['id'];
            //$name = $linkId;
            if (isset($name['name']))
                $name = $name['name'];
        }

        if (isset($data['ajaxLinkId']))
            $linkId = $data['ajaxLinkId'];

        $data['theLinkId'] = $linkId;

        $data['ajaxLinkId'] = $linkId == NULL ? $sender->getName() . "_" . str_replace(" ", "_", $name) : $sender->getName() . "_" . str_replace(" ", "_", $linkId);

        if (isset($data['controlData'])) {
            $controlData = $data['controlData'];
            unset($data['controlData']);
        } else
            $controlData = $updateControl->parseIntoArray();

        if (isset($data['senderData'])) {
            $senderData = $data['senderData'];
            unset($data['senderData']);
        } else
            $senderData = $sender->parseIntoArray();

        $viewData['control'] = $controlData;
        $viewData['sender'] = $senderData;
        $viewData['updateControl'] = $controlData;

        return $this->createAjaxScript($name, $url, $ajaxContainerId, array('view' => $layoutView,
                    'data' => $viewData), $data);
    }

    public function parseIntoArray($data = NULL) {
        $controlData = array();
        //if ($this instanceof BUIAjaxControl) {
        $controlData['class'] = get_class($this);
        $controlData['id'] = $this->getId();

        if ($this instanceof BUIControl) {
            $controlData['ajaxContainerId'] = $this->getAjaxContainerId();
            $controlData['layoutView'] = $this->getLayoutView();
            $controlData['name'] = $this->getName();
            $controlData['class'] = get_class($this);
        }

        if ($this instanceof BUIScreen) {
            //$controlData['class'] = get_class($this);
            //$controlData['id'] = $this->getId();
            $controlData['name'] = $this->getName();
        }

        if ($this instanceof BUIScreenFlow) {
            ////$controlData['class'] = get_class($this);
            //$controlData['id'] = $this->getId();
            $controlData['name'] = $this->getName();
            $controlData['index'] = $this->getIndex();
        }

        if ($this->getNode() != NULL) {
            $controlData['nodeId'] = $this->getNode()->getId();
            $controlData['nodeClass'] = get_class($this->getNode());
            $parsedData = self::parseActiveNode($this->getNode());
            if (isset($parsedData['activeSpace'])) {
                $space = $parsedData['activeSpace'];
                $controlData['activeSpace']['class'] = get_class($space);
                $controlData['activeSpace']['id'] = $space->getId();
            }
            if (isset($parsedData['activeApp'])) {
                $app = $parsedData['activeApp'];
                $controlData['activeApp']['class'] = get_class($app);
                $controlData['activeApp']['id'] = $app->getId();
            }
            if (isset($parsedData['activeOperationFlow'])) {
                $opFlow = $parsedData['activeOperationFlow'];
                $controlData['activeOperationFlow']['class'] = get_class($opFlow);
                $controlData['activeOperationFlow']['id'] = $opFlow->getId();
            }
            if (isset($parsedData['activeOperation'])) {
                $operation = $parsedData['activeOperation'];
                $controlData['activeOperation']['class'] = get_class($operation);
                $controlData['activeOperation']['id'] = $operation->getId();
            }
        }

        return $controlData;
    }

    public static function parseActiveNode($node, $isParsedIntoArray = FALSE) {
        /*
          $activeNode = NULL;
          $activeSpace = NULL;
          $activeApp = NULL;
          $activeOperationFlow = NULL;
          $activeOperation = NULL;
         * 
         */

        $parsedData = array();

        if ($node instanceof BNode) {
            //$activeNode = $node;
            $parsedData['activeNode'] = $node;
        }

        if ($node instanceof BSpace) {
            $parsedData['activeSpace'] = $node;
        }

        if ($node instanceof BApp) {
            $parsedData['activeSpace'] = $node->getCurrentSpace();
            $parsedData['activeApp'] = $node;
        }

        if ($node instanceof BOperationFlow) {
            $parsedData['activeSpace'] = $node->getCurrentApp()->getCurrentSpace();
            $parsedData['activeApp'] = $node->getCurrentApp();
            $parsedData['activeOperationFlow'] = $node;
        }

        if ($node instanceof BOperation) {
            $parsedData['activeSpace'] = $node->getCurrentApp()->getCurrentSpace();
            $parsedData['activeApp'] = $node->getCurrentApp();
            $parsedData['activeOperation'] = $node;
            if ($node->getCurrentOperationFlow() != NULL) {
                $parsedData['activeOperationFlow'] = $node->getCurrentOperationFlow();
            }
        }

        return $parsedData;
    }

    public static function restoreFromArray($data) {
        $controlData = $data;
        $control = NULL;

        if (isset($controlData['class'])) {
            $class = $controlData['class'];

            //$control = new $class();

            if (isset($controlData['nodeClass'])) {
                $nodeClass = $controlData['nodeClass'];
                if (isset($controlData['nodeId'])) {
                    $node = new $nodeClass($controlData['nodeId']);

                    if ($node instanceof BNode) {
                        $className = preg_replace('/^B/', 'BUI', $nodeClass);
                        if ($class == $className)
                            $control = new $class($node);
                        elseif ($node instanceof BApp && $class == 'BUIApp')
                            $control = new $class($node);
                        elseif ($node instanceof BOperationFlow && $class == 'BUIOperationFlow')
                            $control = new $class($node);
                        elseif ($node instanceof BOperation && $class == 'BUIOperation')
                            $control = new $class($node);
                        else {
                            $control = new $class();
                            $control->setNode($node);
                        }
                    }

                    if ($control instanceof BUIScreenFlow) {
                        if (isset($controlData['index'])) {
                            $index = $controlData['index'];
                            $control->setIndex($index);
                        }
                    }

                    if ($control instanceof BUIControl) {
                        if (isset($controlData['ajaxContainerId']) && $controlData['ajaxContainerId'] != NULL)
                            $control->setAjaxContainerId($controlData['ajaxContainerId']);
                        if (isset($controlData['layoutView']) && $controlData['layoutView'] != NULL)
                            $control->setLayoutView($controlData['layoutView']);
                        if (isset($controlData['name']) && $controlData['name'] != NULL)
                            $control->name = $controlData['name'];
                    }
                }

                return $control;
            }

            //return $control;
        }
        return FALSE;
    }

    public static function parseRequest() {

        $activeControl = NULL;
        $parsedData = array();

        //$controller = yii::app()->getController();
        $request = yii::app()->request;
        //$views = array();
        if ($request->isAjaxRequest) {

            //first get ajaxLinkId from request
            $ajaxLinkId = isset($_REQUEST['b_ajaxLinkId']) ? $_REQUEST['b_ajaxLinkId'] : NULL;

            //then get view and view data for rendering according to ajaxLinkId
            if ($ajaxLinkId != NULL) {
                $currentAjaxView = Blyn::app()->getCurrentUser()->getContextVariable('currentAjaxViews');

                if (is_array($currentAjaxView)) {
                    $view = $currentAjaxView[$ajaxLinkId]['view'];
                    $viewData = isset($currentAjaxView[$ajaxLinkId]['data']) ? $currentAjaxView[$ajaxLinkId]['data'] : NULL;

                    if ($viewData != NULL) {
                        Blyn::app()->getUIManager()->addActiveLinkData($viewData);
                    }

                    //below code is useful to compatiable with old code
                    if (isset($viewData['uiObj'])) {
                        if (!isset($viewData['control']) || $viewData['control'] == NULL)
                            $viewData['control'] = $viewData['uiObj'];
                    }
                    if (isset($viewData['uiNode'])) {
                        if (!isset($viewData['control']) || $viewData['control'] == NULL)
                            $viewData['control'] = $viewData['uiNode'];
                    }
                    if (isset($viewData['updateControl'])) {
                        $viewData['control'] = $viewData['updateControl'];
                    }

                    //end compatiable code

                    if (isset($viewData['control'])) {
                        $controlData = $viewData['control'];

                        if (!isset($viewData['sender']))
                            $viewData['sender'] = $controlData;
                    }

                    //$gotoNodeData = Blyn::app()->getCurrentUser()->getContextVariable('gotoNode');
                    //if($gotoNodeData != NULL)
                    //  $viewData['sender'] = $gotoNodeData;

                    if (isset($viewData['sender'])) {
                        $senderData = $viewData['sender'];

                        if (isset($senderData['activeSpace'])) {
                            $id = $senderData['activeSpace']['id'];
                            $class = $senderData['activeSpace']['class'];
                            $activeSpace = new $class($id);
                            if ($activeSpace instanceof BSpace) {
                                Blyn::app()->setActiveSpace($activeSpace);
                                Blyn::app()->setCurrentNode($activeSpace);
                                //Blyn::app()->getUIManager()->setCurrentScreen(Blyn::app()->getActiveSpace()->getUIManager()->getCurrentScreen());
                                //Blyn::app()->getUIManager()->setCurrentScreenFlow(Blyn::app()->getActiveSpace()->getUIManager()->getCurrentScreenFlow());
                                Blyn::app()->getUIManager()->setCurrentScreen(NULL);
                                Blyn::app()->getUIManager()->setCurrentScreenFlow(NULL);
                            }
                            //$parsedData['activeSpace'] = $activeSpace;
                        }

                        if (isset($senderData['activeApp'])) {
                            $id = $senderData['activeApp']['id'];
                            $class = $senderData['activeApp']['class'];
                            $activeApp = new $class($id);
                            if ($activeApp instanceof BApp) {
                                Blyn::app()->setActiveApp($activeApp);
                                Blyn::app()->setCurrentNode($activeApp);
                                Blyn::app()->getUIManager()->setCurrentScreen(NULL);
                                Blyn::app()->getUIManager()->setCurrentScreenFlow(NULL);
                            }
                            //$parsedData['activeApp'] = $activeApp;
                        }

                        if (isset($senderData['activeOperationFlow'])) {
                            $id = $senderData['activeOperationFlow']['id'];
                            $class = $senderData['activeOperationFlow']['class'];
                            $activeOpFlow = new $class($id);
                            if ($activeOpFlow instanceof BOperationFlow) {
                                Blyn::app()->setActiveOperationFlow($activeOpFlow);
                                Blyn::app()->setCurrentNode($activeOpFlow);
                                Blyn::app()->getUIManager()->setCurrentScreen(NULL);
                                Blyn::app()->getUIManager()->setCurrentScreenFlow(NULL);
                            }
                            //$parsedData['activeOperationFlow'] = $activeOpFlow;
                        }

                        if (isset($senderData['activeOperation'])) {
                            $id = $senderData['activeOperation']['id'];
                            $class = $senderData['activeOperation']['class'];
                            $activeOperation = new $class($id);
                            if ($activeOperation instanceof BOperation) {
                                Blyn::app()->setActiveOperation($activeOperation);
                                Blyn::app()->setCurrentNode($activeOperation);
                                Blyn::app()->getUIManager()->setCurrentScreen(NULL);
                                Blyn::app()->getUIManager()->setCurrentScreenFlow(NULL);
                            }
                            //$parsedData['activeOperation'] = $activeOperation;
                        }

                        $senderControl = BUIControl::restoreFromArray($senderData);
                        Blyn::app()->setCurrentNode($senderControl->getNode());

                        if ($senderControl instanceof BUIScreenFlow) {
                            Blyn::app()->getUIManager()->setCurrentScreenFlow($senderControl);
                        } elseif ($senderControl instanceof BUIScreen) {
                            Blyn::app()->getUIManager()->setCurrentScreen($senderControl);
                        } elseif (!$senderControl instanceof BUINode) {
                            //Blyn::app()->getUIManager()->getCurrentScreen()->addControl($senderControl);
                        }

                        $updateControl = BUIControl::restoreFromArray($controlData);

                        if ($updateControl instanceof BUIBlyn)
                            $updateControl = Blyn::app()->getUIManager();
                        elseif ($updateControl instanceof BUISpace)
                            $updateControl = Blyn::app()->getActiveSpace()->getUIManager();
                        elseif ($updateControl instanceof BUIApp)
                            $updateControl = Blyn::app()->getActiveApp()->getUIManager();
                        elseif ($updateControl instanceof BUIOperationFlow)
                            $updateControl = Blyn::app()->getActiveOperationFlow()->getUIManager();
                        elseif ($updateControl instanceof BUIOperation)
                            $updateControl = Blyn::app()->getActiveOperation()->getUIManager();
                        elseif ($updateControl instanceof BUIScreenFlow) {
                            $updateControl = Blyn::app()->getUIManager()->getCurrentScreenFlow();
                        } elseif ($updateControl instanceof BUIScreen) {
                            $updateControl = Blyn::app()->getUIManager()->getCurrentScreen();
                        } elseif ($updateControl instanceof BUIControl) {
                            //$updateControl = Blyn::app()->getUIManager()->getCurrentScreen()->getChildControl($updateControl->getName());
                        }


                        if ($updateControl instanceof BUIControl) {
                            //$control->render();
                            $viewData['control'] = $updateControl;
                        }

                        $parsedData = array('view' => $view, 'data' => $viewData,
                            'activeControl' => $senderControl, 'updateControl' => $updateControl);
                    }

                    return $parsedData;

                    //$this->renderView($view, $viewData);
                }
            }
        } else {
            //first get ajaxLinkId from request
            $linkId = isset($_REQUEST['b_linkId']) ? $_REQUEST['b_linkId'] : NULL;
            $linkIndex = isset($_REQUEST['theLinkIndex']) ? $_REQUEST['theLinkIndex'] : NULL;

            //then get view and view data for rendering according to ajaxLinkId
            if ($linkId != NULL) {
                $rLinkId = $linkId;
                if ($linkIndex != NULL)
                    $rLinkId = $linkId . '_' . $linkIndex;
                $linkData = Blyn::app()->getCurrentUser()->getContextVariable($rLinkId);

                if ($linkData != NULL) {
                    Blyn::app()->getUIManager()->addActiveLinkData($linkData);
                }

                if (isset($linkData['activeSpace'])) {
                    $id = $linkData['activeSpace']['id'];
                    $class = $linkData['activeSpace']['class'];
                    $activeSpace = new $class($id);
                    if ($activeSpace instanceof BSpace) {
                        Blyn::app()->setActiveSpace($activeSpace);
                        //Blyn::app()->setCurrentNode($activeSpace);
                    }
                    //$parsedData['activeSpace'] = $activeSpace;
                }

                if (isset($linkData['activeApp'])) {
                    $id = $linkData['activeApp']['id'];
                    $class = $linkData['activeApp']['class'];
                    $activeApp = new $class($id);
                    if ($activeApp instanceof BApp) {
                        Blyn::app()->setActiveApp($activeApp);
                        //Blyn::app()->setCurrentNode($activeApp);
                    }
                    //$parsedData['activeApp'] = $activeApp;
                }

                if (isset($linkData['activeOperationFlow'])) {
                    $id = $linkData['activeOperationFlow']['id'];
                    $class = $linkData['activeOperationFlow']['class'];
                    $activeOpFlow = new $class($id);
                    if ($activeOpFlow instanceof BOperationFlow) {
                        Blyn::app()->setActiveOperationFlow($activeOpFlow);
                        //Blyn::app()->setCurrentNode($activeOpFlow);
                    }
                    //$parsedData['activeOperationFlow'] = $activeOpFlow;
                }

                if (isset($linkData['activeOperation'])) {
                    $id = $linkData['activeOperation']['id'];
                    $class = $linkData['activeOperation']['class'];
                    $activeOperation = new $class($id);
                    if ($activeOperation instanceof BOperation) {
                        Blyn::app()->setActiveOperation($activeOperation);
                        //Blyn::app()->setCurrentNode($activeOperation);
                    }
                    //$parsedData['activeOperation'] = $activeOperation;
                }

                $activeControl = self::restoreFromArray($linkData);

                if ($activeControl instanceof BUIControl)
                    Blyn::app()->setCurrentNode($activeControl->getNode());

                $parsedData = array(//'view' => $view, 'data' => $viewData,
                    'activeControl' => $activeControl, 'updateControl' => $activeControl);
            }
            else {
                //$controller = yii::app()->getController();
                $url = $request->url;
                $baseUrl = $request->baseUrl;
                //$uri = $request->requestUri;
                if ($url === $baseUrl . "/index.php") {
                    Blyn::app()->setActiveSpace(NULL);
                    Blyn::app()->setActiveApp(NULL);
                    Blyn::app()->setActiveOperationFlow(NULL);
                    Blyn::app()->setActiveOperation(NULL);
                }
            }
            return $parsedData;
        }
    }

    public function isAjaxLinkClicked($name, $layoutView = NULL) {
        if (!yii::app()->request->isAjaxRequest)
            return;
        if ($layoutView == NULL)
            $layoutView = $this->getLayoutView();

        if (is_array($name) && isset($name['ajaxLinkId']))
            $ajaxLinkId = $this->getName() . "_" . str_replace(" ", "_", $name['ajaxLinkId']);
        else if (is_array($name) && isset($name['linkId']))
            $ajaxLinkId = $this->getName() . "_" . str_replace(" ", "_", $name['linkId']);
        else if (is_array($name) && isset($name['id']))
            $ajaxLinkId = $this->getName() . "_" . str_replace(" ", "_", $name['id']);
        else
            $ajaxLinkId = $this->getName() . "_" . str_replace(" ", "_", $name);

        $ajaxLinkId = md5($ajaxLinkId);

        if (isset($_REQUEST['b_ajaxLinkId']) && ($_REQUEST['b_ajaxLinkId'] === $ajaxLinkId)) {
            Blyn::app()->getUIManager()->setActiveLink($ajaxLinkId);
            return TRUE;
        }

        return FALSE;
    }

    public function isLinkClicked($name, $layoutView = NULL) {

        if (yii::app()->request->isAjaxRequest)
            return;

        $activeNode = $this;

        if ($activeNode instanceof BUIBlyn)
            $linkId = 'b_linkId';
        else if ($activeNode instanceof BUISpace)
            $linkId = 'sp_' . $activeNode->getNode();
        else if ($activeNode instanceof BUIApp) {
            $linkId = 'ap_' . $activeNode->getId();
        } else if ($activeNode instanceof BUIOperationFlow) {
            $linkId = 'of_' . $activeNode->getId();
        } else if ($activeNode instanceof BUIOperation)
            $linkId = 'op_' . $activeNode->getId();
        else if ($activeNode instanceof BUIScreenFlow)
            $linkId = 'sf_' . $activeNode->getId();
        else if ($activeNode instanceof BUIScreen)
            $linkId = 'scn_' . $activeNode->getId();
        else
            $linkId = 'con_' . $activeNode->getId();

        $linkId = $linkId . '_' . strtolower(str_replace(' ', '_', $name));

        $linkId = md5($linkId);

        if (isset($_REQUEST['b_linkId']) && ($_REQUEST['b_linkId'] === $linkId)) {
            Blyn::app()->getUIManager()->setActiveLink($linkId);
            return TRUE;
        }

        return FALSE;
    }

    //set default id
    /*
      public function getId() {

      $nodeClass = get_class($this->getNode());
      $nodeId = $this->getNode()->getId();
      $className = strtolower(get_class($this));

      if ($this instanceof BUINode || $this instanceof BUIScreenFlow || $this instanceof BUIScreen)
      $this->id = strtolower($nodeClass) . "_" . $nodeId . "_" . strtolower($className) . "_" . str_replace(' ', '_', $this->getName());
      else
      $this->id = Blyn::app()->getUIManager()->getCurrentScreen()->getId() . "_" . $className . "_" . $this->getName();

      return $this->id;

      //return Blyn::app()->getUIManager()->getCurrentScreen()->getId() . "_" . $this->getName();
      }
     * 
     */

    public function getNode() {
        if ($this->node == NULL)
            $this->node = Blyn::app()->getCurrentNode();
        return $this->node;
    }

    public function setNode($node) {
        if ($node instanceof BNode)
            $this->node = $node;
    }

    public function getAjaxContainerId($data = null) {
        if ($this->ajaxContainerId == NULL)
            $this->ajaxContainerId = "show_" . $this->getName() . "_content";
        return $this->ajaxContainerId;
    }

    public function setAjaxContainerId($ajaxContainerId) {
        $this->ajaxContainerId = $ajaxContainerId;
    }

    /**
     * in some view, can also add ajaxUIObj into view by using this function
     * to show ajaxContainerView
     * @param type $data
     * @return type
     */
    public function getAjaxContainerView($data = NULL) {
        if ($this->containerView == NULL)
            $this->containerView = "ajaxControl_container";
        return $this->containerView;
    }

    public function setAjaxContainerView($containerView) {
        $this->containerView = $containerView;
    }

    public function getLayoutView($data = null) {
        if ($this->layoutView == NULL)
            $this->layoutView = "list_layout";
        return $this->layoutView;
    }

    public function getAngularControllerDefine($data = NULL) {
        $name = $this->getName();
        return 'bng' . ucfirst($name) . 'Controller';
    }

    public function setLayoutView($layoutView) {
        $this->layoutView = $layoutView;
    }

    public function addRenderView($name, $viewName = null, $viewData = NULL) {
        if ($viewName == NULL)
            $viewName = $name;
        if (!is_array($viewData))
            $viewData = array();
        if (!isset($viewData['control']))
            $viewData['control'] = $this;
        parent::addRenderView($name, $viewName, $viewData);
    }

    public function addView($name, $viewName = null, $viewData = NULL) {
        $this->addRenderView($name, $viewName, $viewData);
    }

    public function addViews($views = array()) {
        if (is_string($views) && $views != NULL)
            $this->views[$views] = array('view' => $views);

        if (is_array($views)) {
            foreach ($views as $name => $view) {
                if (is_string($view)) {
                    if (is_numeric($name))
                        $name = $view;
                    $this->addRenderView($name, $view);
                }
                if (is_array($view)) {
                    $aView = array();
                    if (isset($view['view']))
                        $aView = $view['view'];
                    if (isset($view['data'])) {
                        $aData = $view['data'];
                    }
                    if (is_numeric($name))
                        $name = $aView;
                    $this->addRenderView($name, $aView, $aData);
                }
            }
        }
    }

    public function getViews() {
        return $this->views;
    }

    public function setViews($views) {
        if ($views == NULL)
            $views = array();
        $this->views = $views;
    }

    public function getName($data = NULL) {
        if ($this->name == NULL) {
            if (!$this instanceof BUIBlyn && !$this instanceof BUINode && !$this instanceof BUIScreen)
                $this->name = get_class($this) . "_" . Blyn::app()->getUIManager()->getCurrentScreen()->getControlCount();
        }
        //else {
        //$this->name = get_class($this) . "_" . self::getUniqueId();
        //}
        // }

        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
    }

    public function getUrl($params = array(), $route = 'site/index', $ampersand = '&') {

        if ($params == NULL)
            $params = array();
        $urlData = array($route);

        foreach ($params as $key => $value) {
            $urlData[$key] = $value;
        }

        return $urlData;
    }

    //this function will return none-ajax link,default route is 'site/index'
    public function getLink($name, $data = array(), $sender = NULL, $route = 'site/index', $params = array(), $ampersand = '&') {

        $class = '';
        $htmlOptions = array();
        if (is_array($data)) {
            if (isset($data['class'])) {
                $class = $data['class'];
                unset($data['class']);
            }
            if (isset($data['htmlOptions'])) {
                $htmlOptions = $data['htmlOptions'];
                unset($data['htmlOptions']);
            }
            foreach ($data as $key => $value) {
                if (is_string($value) || is_numeric($value)) {
                    $params[$key] = $value;
                    unset($data[$key]);
                }
            }
        }

        $linkId = NULL;
        if (is_array($name) && isset($name['name']) && $name['name'] != NULL) {
            if (isset($name['linkId']))
                $linkId = $name['linkId'];
            if (isset($name['id']))
                $linkId = $name['id'];
            $aName = $name['name'];
        }
        if (is_string($name))
            $aName = $name;


        $url = $this->getLinkUrl($name, $params, $sender, $route, $data, $ampersand);

        if (isset($htmlOptions['class']))
            $class = $htmlOptions['class'];

        $htmlOptionString = '';
        foreach ($htmlOptions as $tag => $value) {
            $htmlOptionString .= $tag . "='" . $value . "'";
        }

        return '<a href = "' . $url . '" ' . $htmlOptionString . '>' . $aName . '</a>';
    }

    public function getLinkUrl($name = null, $params = array(), $sender = null, $route = 'site/index', $data = array(), $ampersand = '&') {
        if ($route == NULL)
            $route = 'site/index';

        $controller = yii::app()->getController();

        $activeNode = $this;

        if ($sender instanceof BUIControl)
            $activeNode = $sender;

        if ($activeNode instanceof BUIBlyn)
            $params['b_linkId'] = 'b_linkId';
        else if ($activeNode instanceof BUISpace)
            $params['b_linkId'] = 'sp_' . $activeNode->getId();
        else if ($activeNode instanceof BUIApp) {
            $params['b_linkId'] = 'ap_' . $activeNode->getId();
        } else if ($activeNode instanceof BUIOperationFlow) {
            $params['b_linkId'] = 'of_' . $activeNode->getId();
        } else if ($activeNode instanceof BUIOperation)
            $params['b_linkId'] = 'op_' . $activeNode->getId();
        else if ($activeNode instanceof BUIScreenFlow)
            $params['b_linkId'] = 'sf_' . $activeNode->getId();
        else if ($activeNode instanceof BUIScreen)
            $params['b_linkId'] = 'scn_' . $activeNode->getId();
        else
            $params['b_linkId'] = 'con_' . $activeNode->getId();

        $linkId = NULL;
        if (is_string($name)) {
            $linkId = $name;
        }
        if (is_array($name)) {
            if (isset($name['linkId']))
                $linkId = $name['linkId'];
            if (isset($name['id']))
                $linkId = $name['id'];
            if (isset($name['name']))
                $name = $name['name'];
        }

        $params['theLinkId'] = $linkId;

        if (!isset($this->linkIndex[$linkId])) {
            $this->linkIndex[$linkId] = 1;
        } else {
            $this->linkIndex[$linkId] ++;
        }
        $params['theLinkIndex'] = $this->linkIndex[$linkId];

        if ($linkId != NULL)
            $params['b_linkId'] = md5($params['b_linkId'] . '_' . strtolower(str_replace(' ', '_', $linkId)));
        //$params['b_linkId'] = md5($linkId);
        else {
            $params['b_linkId'] = md5($params['b_linkId'] . '_' . strtolower(str_replace(' ', '_', $name)));
        }

        foreach ($params as $key => $value) {
            if (!is_string($value) && !is_numeric($value)) {
                $data[$key] = $value;
                unset($params[$key]);
            }
        }

        foreach ($data as $key => $value) {
            if (is_string($value) || is_numeric($value)) {
                $params[$key] = $value;
                unset($data[$key]);
            }
        }

        Blyn::app()->getCurrentUser()->addContextVariable($params['b_linkId'], $activeNode->parseIntoArray());
        //add data for link and then can retrieve
        if (is_array($data) && !empty($data)) {
            $linkIndex = $params['theLinkIndex'];
            Blyn::app()->getCurrentUser()->addContextVariable($params['b_linkId'] . '_' . $linkIndex, $data);
        }

        $url = $controller->createUrl($route, $params, $ampersand);

        return $url;
    }

    /**
     * this function is use to add ajaxUIObj to screen for rendering
     * @param type $data
     */
    public function addToParentControl($parent = NULL) {
        if (!$parent instanceof BUIBase)
            $parent = Blyn::app()->getUIManager()->getCurrentScreen();
        $parent->addRenderView($this->getName(), $this->getAjaxContainerView(), array('control' => $this));
    }

    /**
     * this function use to show ajaxUIObj when use javascript
     * @param type $data
     */
    public function renderControlContainer($data = NULL) {
        //$this->renderView($this->getAjaxContainerView(), array('control' => $this));
        $containerId = $this->getAjaxContainerId();
        $layoutView = $this->getLayoutView();
        echo "<div id=" . $containerId . ">";

        $this->renderView('ajaxControl_beforeLoad', array('control' => $this));
        $this->renderView($layoutView, array('control' => $this));

        echo "</div>";
    }

    public function renderControlLayout($layOutView = NULL) {

        if ($layOutView != NULL)
            $this->layoutView = $layOutView;

        $this->renderView($this->getLayoutView(), array('control' => $this));
    }

    public function renderControlView($view = NULL) {
        if ($view != NULL)
            $this->renderView($view, array('control' => $this));
    }

    public function renderView($view, $data = NULL, $uiNode = NULL) {
        if ($data == NULL)
            $data = array();
        if (is_array($data)) {
            if (!isset($data['control'])) {
                $data['control'] = $this;
                if ($uiNode != NULL) {
                    $data['control'] = $uiNode;
                }
            }
        }
        return parent::renderView($view, $data, $this);
    }

    /**
     * 
     * @param type $data
     */
    public function render($data = NULL) {

        if ($this->isRendered)
            return;

        //prepare first
        $this->prePare($data);

        //call render first
        $this->isRendered = TRUE;
        $this->onRender($data);

        $containerId = $this->getAjaxContainerId();
        $layoutView = $this->getLayoutView();
        echo "<div id=" . $containerId . ">";

        $this->renderView('ajaxControl_beforeLoad', array('control' => $this));
        $this->renderView($layoutView, array('control' => $this));

        echo "</div>";
    }

    public function renderContent($data = NULL) {
        if ($this->isRendered)
            return;

        //prepare first
        $this->prePare($data);

        //call render first
        $this->isRendered = TRUE;
        $this->onRender($data);

        $containerId = $this->getAjaxContainerId();
        $layoutView = $this->getLayoutView();


        $this->renderView('ajaxControl_beforeLoad', array('control' => $this));
        $this->renderView($layoutView, array('control' => $this));
    }

    public final function run($data = NULL) {

        $this->onRun($data);

        $activeLink = Blyn::app()->getUIManager()->getActiveLink();
        $linkId = NULL;
        if ($activeLink instanceof BUILink)
            $linkId = $activeLink->getLinkVariable('theLinkId');

        //for each link of control, if method of 'onLinkId' exist, will call it
        if ($linkId != NULL) {
            if (ctype_alnum($linkId)) {//if linkId is aphabic and digit 
                $onMethod = 'on' . ucfirst($linkId);
                if (method_exists($this, $onMethod)) {
                    $this->$onMethod($data);
                }
            }
        } else {//if not click on linkId, show home
            $this->onShowHome($data);
        }


        $controls = $this->getChildrenOfControl();

        //so, please add child control in 'onRun' function
        foreach ($controls as $control) {
            if ($control instanceof BUIControl) {
                $control->run($data);
            }
        }
    }

    public function onRun($data = NULL) {
        
    }

    //use to show Home page
    public function onShowHome($data = NULL) {
        
    }

    public function addChildControl($control, $name = NULL) {
        return $this->addControl($control, $name);
    }

    public function removeChildControl($name) {
        if (isset($this->controls[$name])) {
            unset($this->controls[$name]);
            return TRUE;
        }
        return FALSE;
    }

    public function getChildControl($name) {
        return $this->controls[$name];
    }

    public function getChildrenOfControl($context = NULL) {
        return $this->controls;
    }

    public function addChildrenOfControl($controlList = array()) {
        foreach ($controlList as $name => $control) {
            if ($control instanceof BUIControl) {
                $this->controls[$name] = $control;
                $control->setParentControl($this);
            }
        }
    }

    /**
     * overridable function
     * @param type $data
     */
    public function onRender($data = NULL) {
        if (!$this instanceof BUIBlyn) {
            $activeLink = Blyn::app()->getUIManager()->getActiveLink();
            if ($activeLink instanceof BUILink) {
                $template = $activeLink->getLinkVariable('template');
                if ($template != NULL) {
                    $this->setViewTemplate($template);
                }
            }
        }
    }

    //use to add child control
    public function addControl($control, $name = NULL) {
        if ($name == NULL)
            $name = $control->getName();
        if ($name == NULL)
            $name = get_class($control) . '_' . Blyn::app()->getUnicodeId();

        if ($control instanceof BUIControl) {
            $control->parentControl = $this;
            $this->controls[$name] = $control;
        }
    }

    public function registerCss($cssCode, $data = NULL) {
        
    }

    public function registerCssFile($files, $data = NULL) {
        
    }

    public function registerScript($script, $data = NULL) {
        
    }

    public function registerScriptFile($files, $data = NULL) {
        
    }

    public function getViewPath($data = NULL) {
        return $this->viewPath;
    }

    public function getRelativeViewPath($data = NULL) {
        $viewPath = $this->getViewPath();
        if ($viewPath != NULL) {
            $appViewPath = Blyn::app()->getActiveApp()->getUIManager()->getViewPath();
            $viewPath = str_replace($appViewPath . '.', '', $viewPath);
            return $viewPath;
        }
        return FALSE;
    }

    public function setViewPath($viewPath) {
        $this->viewPath = $viewPath;
    }

    public function getViewTemplate($data = NULL) {
        return $this->viewTemplate;
    }

    public function setViewTemplate($viewTemplate) {
        return $this->viewTemplate = $viewTemplate;
    }

    //
    public function setParentControl($parent, $data = NULL) {
        if ($parent instanceof BUIControl)
            $this->parentControl = $parent;
    }

    public function getParentControl($data = NULL) {
        return $this->parentControl;
    }

    public function onParseRequest($data = NULL) {
        
    }

    public function onPrePare($data = NULL) {
        
    }

    public function prePare($data = NULL) {
        if (!$this->isPrepared) {
            $this->onParseRequest();
            $this->onPrePare($data);
            foreach ($this->controls as $control) {
                if ($control instanceof BUIControl) {
                    $control->prePare($data);
                }
            }
            $this->isPrepared = TRUE;
        }
    }

    public function beginCache($id, $properties = array()) {

        $cacheId = $this->getId() . '_' . $id;

        yii::app()->getController()->beginCache($cacheId, $properties);
    }

    public function endCache() {
        yii::app()->getController()->endCache();
    }

}

?>
